package gameLogic

import (
	"net"
	"server_cluster/common/config"
	"server_cluster/common/logger"
	"server_cluster/common/myepoll"
	"server_cluster/common/mysock"
	"server_cluster/common/protoc/pb"
	"server_cluster/common/sharedb"
	"server_cluster/common/tools"
	"server_cluster/gate/db"
	"server_cluster/gate/gate_config"
	"server_cluster/gate/sharemem"

	"google.golang.org/protobuf/proto"
)

func NoticeServerUserStatus(Type int8, Sid int16, Uid int64, status uint32) {
	mybuf := mysock.Create()
	mybuf.Command = status
	mybuf.Session = uint64(Uid)
	mybuf.WriteToServer(Type,Sid,nil)
}

// 通知所有相关服务器 用户已下线
func NoticeAllServerUserOffline(shm_user *sharemem.User) {
	NoticeServerUserStatus(myepoll.CONN_TYPE_LOGIC, shm_user.Lserver, shm_user.Uid, config.SS_User_Offline)
	NoticeServerUserStatus(myepoll.CONN_TYPE_CHAT_ROOT, 0, shm_user.Uid, config.SS_User_Offline)
}

// 通知所有相关服务器 用户已上线
func NoticeAllServerUserOnline(shm_user *sharemem.User) {
	NoticeServerUserStatus(myepoll.CONN_TYPE_CHAT_ROOT, 0, shm_user.Uid, config.SS_User_Online)
}

func CleanClient(fd int32) {
	var myshm = sharemem.Myshm
	eps := &myepoll.Eps
	conn := eps.GetConnByFd(fd)
	if conn != nil && conn.Site >= 0 && conn.Site < gate_config.SHM_USER_MAX {
		if myshm.User[conn.Site].Fd == fd {
			myshm.User[conn.Site].Fd = -1
			if myshm.User[conn.Site].Lserver != 0 {
				//用户下线
				NoticeAllServerUserOffline(&(myshm.User[conn.Site]))
			}
		}
	}
	eps.CleanConn(fd)
}

func sessionCheck(mybuf *mysock.SockBuf, shm_user **sharemem.User, fd int32) uint16 {
	if mybuf.Session == 0 {
		logger.Error("sessionCheck error mybuf.session=0")
		return config.CHECK
	}
	i := tools.DeSession(mybuf.Session)
	if i < 0 || i >= gate_config.SHM_USER_MAX {
		logger.Error("SessionCheck error Desession = %d", i)
		return config.PROTO
	}

	if !sharemem.Myshm.User[i].IsSession(mybuf.Session) {
		logger.Error("SessionCheck error index:%d u.uid:%d u.session=%d mybuf.session=%d", i, sharemem.Myshm.User[i].Uid, sharemem.Myshm.User[i].Session, mybuf.Session)
		return config.CHECK
	}
	*shm_user = &(sharemem.Myshm.User[i])
	if fd != (*shm_user).Fd {
		logger.Error("SessionCheck fd!=Fd fd = %d,Fd = %d", fd, (*shm_user).Fd)
		eps := &myepoll.Eps
		// 断开老连接
		conns := eps.GetConnByFd((*shm_user).Fd)
		if conns != nil && conns.Site == (*shm_user).Index {
			conns.Socket.Close()
			eps.Fds.Delete((*shm_user).Fd)
		}
		(*shm_user).Fd = fd
	}
	return config.OK
}

func SyncStock() {
	cfg := sharedb.Config_server{}
	if !cfg.Update_stock(db.Conn, int16(gate_config.CONF.SERVER_ID), sharemem.Myshm.Stock) {
		logger.Error("update stock error.server id = %d", gate_config.CONF.SERVER_ID)
	}
}

func ServerAction(conn net.Conn, mybuf *mysock.SockBuf, Type int8, Sid int16) {
	defer func() {
		if err := recover(); err != nil {
			logger.Error("!!! Server action LOOP PANIC !!!")
			logger.Error("error: %v", err)
			logger.Error("stack: %v", logger.Stack())
		}
	}()

	if mybuf.Command == config.CSC_Heart {
		// 服务器心跳
		if Heart(conn, mybuf) != config.OK {
			eps := &myepoll.Eps
			eps.CleanServerConn(Type,Sid)
		}
		return
	}
	shm_user := sharemem.GetUserByMapUid(int64(mybuf.Session))
	if shm_user == nil {
		// 未找到，直接返回
		logger.Error("shm_user not found.uid=%d", mybuf.Session)
		return
	}

	switch Type {
	case myepoll.CONN_TYPE_LOGIC:
		switch mybuf.Command {
		case config.SC_Login:
			// 登录返回
			if mybuf.Code == config.OK {
				shm_user.Lserver = Sid
				// 返回login
				res := &pb.SC_Login{}
				tmpData := mybuf.Data[mysock.HEAD_LEN : mysock.HEAD_LEN+mybuf.Data_length]
				err := proto.Unmarshal(tmpData, res)
				if err != nil {
					logger.Error("parse pb msg err: %v, uid: %v", err, shm_user.Uid)
					return
				}
				res.Session = shm_user.Session

				//logger.Info("session=%v,res = %v", shm_user.Session, res)
				data, _ := proto.Marshal(res)
				mybuf.WriteToByFd(shm_user.Fd, data)
				//用户上线
				NoticeAllServerUserOnline(shm_user)
				return
			} else {
				shm_user.Lserver = 0
			}
		case config.SC_Reconnect:
			if mybuf.Code == config.OK {
				//用户重新上线
				NoticeAllServerUserOnline(shm_user)
			}
		case config.SC_Kick_User:
			shm_user.Session = 0
			// 强踢用户下线
			NoticeAllServerUserOffline(shm_user)
			//通知已被踢 session已过期 不用断连接
			mybuf.ForwardWithNewSession(shm_user.Fd, 0)
			return
		case config.CSC_Chat_Msg:
			//chat 消息
			chat_info := pb.CSC_Chat_Msg{}
			err := proto.Unmarshal(mybuf.Data[mysock.HEAD_LEN:mysock.HEAD_LEN+mybuf.Data_length], &chat_info)
			if err != nil {
				logger.Error("CSC_Chat_Msg unmarshal err:%v", err)
				return
			}
			//recv_id := chat_info.GetUid()
			//转发到chat服
			return
		case config.SC_CREATE_BATTLE:
			// 创建战斗->battle
			if mybuf.Code != config.OK {
				break
			}
			create_info := pb.SS_Create_Battle{}
			err := proto.Unmarshal(mybuf.Data[mysock.HEAD_LEN:mysock.HEAD_LEN+mybuf.Data_length], &create_info)
			if err != nil {
				logger.Error("SC_CREATE_BATTLE unmarshal err:%v", err)
				return
			}
			server_id := int16(create_info.GetFightServerId())
			mybuf.ServerForward(myepoll.CONN_TYPE_BATTLE, server_id)
			return
		}
	case myepoll.CONN_TYPE_BATTLE:
		switch mybuf.Command {
		case config.SC_CREATE_BATTLE:
			if mybuf.Code == config.OK {
				shm_user.Bserver = Sid
			} else {
				shm_user.Bserver = 0
			}
		case config.SC_BATTLE_OVER:
			// 战斗结束->logic
			mybuf.ServerForward(myepoll.CONN_TYPE_LOGIC, shm_user.Lserver)
			return
		}
	}
	// 其它->client
	if mybuf.ForwardByFd(shm_user.Fd) != config.OK {
		CleanClient(shm_user.Fd)
	}
}

func Action(conn net.Conn, mybuf *mysock.SockBuf, shm_user **sharemem.User, fd int32) (err_res uint16) {
	defer func() {
		if err := recover(); err != nil {
			logger.Error("!!! client action LOOP PANIC !!!")
			logger.Error("error: %v", err)
			logger.Error("stack: %v", logger.Stack())
			err_res = config.SERVER_PANIC
		}
	}()
	if mybuf.Command != config.CS_Login {
		if sessionCheck(mybuf, shm_user, fd) != config.OK {
			return config.CHECK
		}
	}
	switch mybuf.Command {
	case config.CSC_Heart:
		// 客户端心跳
		if Heart(conn, mybuf) != config.OK {
			CleanClient(fd)
		}
	case config.CS_Login:
		// 处理登录->logic
		Login(conn, mybuf, shm_user, fd)
		if sharemem.Myshm.Stock == 0 {
			// 库存不足 立即同步
			SyncStock()
		}
	default:
		// 默认->logic
		if mybuf.Command != config.CS_CREATE_BATTLE && mybuf.Command > config.BATTLE_BEGIN && mybuf.Command < config.BATTLE_END {
			// 转发->battle
			mybuf.ServerForwardWithNewSession(myepoll.CONN_TYPE_BATTLE,(*shm_user).Bserver,uint64((*shm_user).Uid))
		} else {
			// 转发->logic
			mybuf.ServerForwardWithNewSession(myepoll.CONN_TYPE_LOGIC,(*shm_user).Lserver,uint64((*shm_user).Uid))
		}
	}
	return config.OK
}

func Heart(conn net.Conn, mybuf *mysock.SockBuf) uint16 {
	mybuf.Command = config.CSC_Heart
	u := &pb.CSC_Heart{
		Timenow: sharemem.Myshm.Time_now,
	}
	data, _ := proto.Marshal(u)
	return mybuf.WriteToByConn(conn, data)
}

func ActivePush(mybuf *mysock.SockBuf, user_map *map[int64]*sharemem.User) {
	// 遍历所有战斗，判断是否推送消息
	/*for k,v := range fight_map {
	  }*/
}
